;---------------------------------------------------------------------------
; FileName: finger.asm
; Description:
; extract finger minutiae information from thining image,using neighour area
; find endpoint and burification point
; written by wang zhigang
; Date:   06/25/2000
;---------------------------------------------------------------------------
        .mmregs
        .include "fisc54.inc"
        .ref   CosTable,AtanTable,MaskTable,FreqArray,LightArray,SinValue
        .ref   IMAGEADDR,MaskBitValue,Theta,CoordX,CoordY,Distance,Cal_Distance
        .ref   GrayLevel,FreqValue,EdgePos,EdgePosX,EdgePosY,DeltX,DeltY,CosValue
        .ref   Minus,VertBlock,HorzBlock,BlockLine,BlockCol,Divisor,GetCosValue
        .ref   TangleValue,DivideU32,Cal_Coordinate,GetSinValue,Check_Theta
        .def   MinutiaeExtract,FinalMinutiae,MatchData,Theta1,Theta3
		.def   DistanceX,DistanceY,FindMinutiae,PassMinutiae

;---------------------------------------------------------------------------
FingerMinutiae  .usect "finger_bfr",MAXMINUTIAE*4
;CheckMinutiae   .usect "check_bfr" ,MAXMINUTIAE*4
	.sect "check_bfr"
CheckMinutiae:
   .word  149,14,1,21
   .word  147,21,1,227
   .word  28,28,3,155
   .word  76,42,3,181
   .word  112,43,3,212
   .word  140,43,1,40
   .word  96,57,1,210
   .word  171,58,3,247
   .word  12,86,3,307
   .word  91,72,3,99
   .word  106,75,1,45
   .word  113,78,3,261
   .word  143,84,1,252
   .word  73,90,1,270
   .word  56,116,1,74
   .word  139,109,1,265
   .word  162,111,1,81
   .word  180,103,1,77
   .word  23,127,1,262
   .word  31,127,3,221
   .word  61,119,3,130
   .word  76,124,1,309
   .word  100,125,3,291
   .word  160,125,3,262
   .word  111,149,1,305
   .word  18,155,3,75
   .word  38,153,3,178
   .word  56,157,3,338
   .word  174,156,3,265
   .word  47,182,1,344
   .word  117,168,3,290
   .word  183,188,3,88

Buffer          .usect "find_blk"  ,MAXMINUTIAE
Exist1          .usect "match_blk" ,MAXMINUTIAE
Exist2          .usect "match_blk" ,MAXMINUTIAE
Pos1            .usect "finger_var",MINMATCHPOINTS
Pos2            .usect "finger_var",MINMATCHPOINTS		
AlphaArray      .usect "finger_var",8
OrientArray     .usect "finger_var",8
DeltAlpha       .usect "finger_var",8

;---------------------------------------------------------------------------
; variables used in minutiae extract from fingerprint image
;---------------------------------------------------------------------------
        .bss GraySum            ,2
        .bss OffsetPosX         ,1 
        .bss OffsetPosY         ,1
        .bss OffsetPos          ,1
        .bss Position           ,1
		.bss FreqNum            ,1
        .bss Orient             ,1
        .bss Orient1            ,1
        .bss Orient2            ,1
        .bss OrientNum          ,1
        .bss MinOrient          ,1
        .bss MinDeltAlpha       ,1
        .bss GrayLevel1         ,1
        .bss GrayLevel2         ,1
        .bss MinutiaeCount      ,1
		.bss CheckCount         ,1
        .bss MinutiaePointer    ,1
        .bss Theta0             ,1
        .bss Theta1             ,1
        .bss Theta2             ,1
        .bss Theta3             ,1
        .bss OldCoordX          ,1
		.bss OldCoordY          ,1
		.bss DistanceX          ,1
		.bss DistanceY          ,1
		.bss Distance0          ,1
		.bss Distance1          ,1
		.bss Distance2          ,1
        .bss CosData0           ,1
		.bss SinData0           ,1
		.bss CosData1           ,1
		.bss SinData1           ,1
		.bss CheckIndex         ,1
		.bss CheckIndex1        ,1
		.bss CheckIndex2        ,1
		.bss MinutiaeIndex      ,1
		.bss MinutiaeIndex1     ,1
		.bss MinutiaeIndex2     ,1
		.bss PointOfMatch       ,1
		.bss MatchThreshold     ,1
        .bss MaxMatchPoint      ,1

****************************************************************************
* using neighbour area point to extract endpoint and burificate point
****************************************************************************
        .text
MinutiaeExtract:
        ST   #360,Divisor
        STM  #BLOCKSINY-1,AR4
        STM  #IMAGEADDR-IMAGEOFF+STARTROW*IMAGEWIDTH+STARTCOL,AR5
        STM  #LightArray,AR6
        STM  #FreqArray,AR7
        LD   #FingerMinutiae,A
        STL  A,MinutiaePointer
        ST   #0,VertBlock
		ST   #0,MinutiaeCount
EXTRACT_LINE_LOOP
        STM  #BLOCKSINX-1,AR3
        ST   #0,HorzBlock
EXTRACT_COL_LOOP
        LD   *AR6+,A                ;LightArray
        SUB  #2,A
        BC   NEXT_EXTRACT_COL,ALT
        LD   *AR7,A
        STL  A,FreqValue            ;FreqArray
        LD   #32768,B
        RPT  #15
        SUBC FreqValue,B
        STL  B,1,FreqNum
        MVMM AR5,AR1
        STM  #BLOCKHEIGHT-1,AR2
        STM  #BLOCKHEIGHT,T
        MPY  VertBlock,A
        STL  A,CoordY
EXTRACT_BLOCK_LINE
        SUB  #4,A,B
        BC   NEXT_EXTRACT_BLOCK_LINE,BLT
        SUB  #BLOCKSINY*BLOCKHEIGHT-4,A,B
        BC   NEXT_EXTRACT_BLOCK_LINE,BGEQ
        STM  #BLOCKWIDTH-1,AR0
        STM  #BLOCKWIDTH,T
        MPY  HorzBlock,A
        STL  A,CoordX
EXTRACT_BLOCK_COL
        CMPM MinutiaeCount,#MAXMINUTIAE
        RC   TC                  ;return
        SUB  #4,A,B
        BC   NEXT_EXTRACT_BLOCK_COL,BLT
        SUB  #BLOCKSINX*BLOCKWIDTH-4,A,B
        BC   NEXT_EXTRACT_BLOCK_COL,BGEQ
        CMPM *AR1,#0
        BC   NEXT_EXTRACT_BLOCK_COL,TC
        CALL FindMinutiae
        BC   NEXT_EXTRACT_BLOCK_COL,TC
        CALL PassMinutiae
        BC   NEXT_EXTRACT_BLOCK_COL,TC
        LD   MinutiaeCount,A
        ADD  #1,A
        STL  A,MinutiaeCount
NEXT_EXTRACT_BLOCK_COL
        MAR  *AR1+
        LD   CoordX,A
        ADD  #1,A
        STL  A,CoordX
        BANZ EXTRACT_BLOCK_COL,*AR0-
        MAR  *+AR1(-BLOCKWIDTH)
NEXT_EXTRACT_BLOCK_LINE
        MAR  *+AR1(IMAGEWIDTH)
        LD   CoordY,A
        ADD  #1,A
        STL  A,CoordY
        BANZ EXTRACT_BLOCK_LINE,*AR2-
NEXT_EXTRACT_COL
		MAR  *AR7+
        MAR  *+AR5(BLOCKWIDTH)
        LD   HorzBlock,A
        ADD  #1,A
        STL  A,HorzBlock
        BANZ EXTRACT_COL_LOOP,*AR3-
NEXT_EXTRACT_LINE
        MAR  *+AR5(BLOCKHEIGHT*IMAGEWIDTH-BLOCKSINX*BLOCKWIDTH)
        LD   VertBlock,A
        ADD  #1,A
        STL  A,VertBlock
        BANZ EXTRACT_LINE_LOOP,*AR4-
        RET

****************************************************************************
* find the mintiae point in neighbour area
****************************************************************************
        .text
FindMinutiae:
        PSHM AR0
        PSHM AR2
        PSHM AR3
        PSHM AR4
        PSHM AR5
        PSHM AR6
        PSHM AR7
        SSBX SXM
        ST   #080h,MaskBitValue
        ST   #0,Position
        ST   #0,OrientNum
        SUB  B,B
        STM  #OrientArray,AR6
        STM  #EdgePos,AR7
        STM  #8-1,BRC
        RPTB NEIGHBOR_POINT_LOOP-1
        LDM  AR1,A
        ADD  *AR7+,A
        STLM A,AR0
        NOP
        NOP
        CMPM *AR0,#0
        BC   NEXT_NEIGHBOR_POINT,TC
        STL  B,*AR6+
        LD   Position,A
        XOR  MaskBitValue,A
        STL  A,Position
        LD   OrientNum,A
        ADD  #1,A
        STL  A,OrientNum
NEXT_NEIGHBOR_POINT
        ADD  #1,B
        LD   MaskBitValue,-1,A
        STL  A,MaskBitValue
NEIGHBOR_POINT_LOOP
        LD   #MaskTable,A
        ADD  Position,A
        STLM A,AR0
        LD   OrientNum,B
        SUB  #1,B
        CMPM *AR0,#0
        BC   EXIT_FINDMINUTIAE,TC          ;return FALSE
        CMPM OrientNum,#0
        BC   EXIT_FINDMINUTIAE,TC          ;return FALSE
		 
        STLM B,AR7
        STM  #AlphaArray,AR5
        STM  #OrientArray,AR6
OFFSET_NEIGHBOR_LOOP
        LD   *AR6+,A      ;Orient=OrientArray[OrientIndex]
        STL  A,Orient
        
        ADD  #EdgePos,A,B ;EdgePos[Orient]
        STLM B,AR0
        NOP
        LDM  AR1,B
        ADD  *AR0,B       ;Offset
        STL  B,OffsetPos
		
        ADD  #EdgePosX,A,B
        STLM B,AR0
        NOP
        LD   CoordX,B
        ADD  *AR0,B       ;EdgePos[Orient].x
        STL  B,OffsetPosX

        ADD  #EdgePosY,A,B
        STLM B,AR0
        NOP
        LD   CoordY,B
        ADD  *AR0,B       ;EdgePos[Orient].y
        STL  B,OffsetPosY

        LD   FreqNum,A
        BC   NEXT_OFFSET_NEIGHBOR,ALEQ
        PSHM AR5
        SUB  #1,A
        STLM A,AR3
FREQ_NEIGHBOR_LOOP
        STM  #EdgePos,AR2
        SUB  B,B                ;Position=0
        ST   #080h,MaskBitValue
        STM  #8-1,BRC
        RPTB FIND_NEIGHBOR_LOOP-1
        LD   *AR2+,A
        ADD  OffsetPos,A
        STLM A,AR0
        NOP
        NOP
        CMPM *AR0,#0
        BC   NOT_BLACK_POINT,TC
        XOR  MaskBitValue,B
NOT_BLACK_POINT
        LD   MaskBitValue,-1,A
        STL  A,MaskBitValue
FIND_NEIGHBOR_LOOP
        ADD  #MaskTable,B
        STLM B,AR0
        NOP
        NOP
        CMPM *AR0,#0
        BC   NEXT_FREQ_NEIGHBOR,NTC
        
        SUB  B,B           ;BitCount=0
        STM  #3,AR4
NEIGHBOR_ORIENT_LOOP
        LD   Orient,A
        ADD  B,A           ;Orient1=(Orient+BitCount)%8
        AND  #07h,A
        STL  A,Orient1
        ADD  #EdgePos,A
        STLM A,AR0
        NOP
        NOP
        LD   *AR0,A
        ADD  OffsetPos,A
        STLM A,AR0
        NOP
        NOP
        CMPM *AR0,0
        BC   NEXT_POS_1,TC
        STL  A,OffsetPos
        LD   Orient1,A
        STL  A,Orient
        ADD  #EdgePosX,A
        STLM A,AR0
        LD   Orient1,A
        ADD  #EdgePosY,A
        STLM A,AR5
        LD   *AR0,A
        ADD  OffsetPosX,A
        STL  A,OffsetPosX
        LD   *AR5,A
        ADD  OffsetPosY,A
        STL  A,OffsetPosY
        B    JUDGE_FREQ_NEIGHBOR
NEXT_POS_1
        LD   Orient,A      ;Orient2=(Orient-BitCount+8)%8
        ADD  #8,A
        SUB  B,A
        AND  #07h,A
        STL  A,Orient2
        ADD  #EdgePos,A
        STLM A,AR0
        NOP
        NOP
        LD   *AR0,A
        ADD  OffsetPos,A
        STLM A,AR0
        NOP
        NOP
        CMPM *AR0,0
        BC   NEXT_POS_2,TC
        STL  A,OffsetPos
        LD   Orient2,A
        STL  A,Orient
        ADD  #EdgePosX,A
        STLM A,AR0
        LD   Orient2,A
        ADD  #EdgePosY,A
        STLM A,AR5
        LD   *AR0,A
        ADD  OffsetPosX,A
        STL  A,OffsetPosX
        LD   *AR5,A
        ADD  OffsetPosY,A
        STL  A,OffsetPosY
        B    JUDGE_FREQ_NEIGHBOR
NEXT_POS_2
        ADD  #1,B
        BANZ NEIGHBOR_ORIENT_LOOP,*AR4-
JUDGE_FREQ_NEIGHBOR
        SUB  #4,B
        BC   RESTORE_OFFSET_NEIGHBOR,BEQ
NEXT_FREQ_NEIGHBOR
        BANZ FREQ_NEIGHBOR_LOOP,*AR3-
RESTORE_OFFSET_NEIGHBOR
        POPM AR5
NEXT_OFFSET_NEIGHBOR
        LD   CoordX,A
        SUB  OffsetPosX,A
        STM  #DeltX,AR0
        DST  A,*AR0
        LD   CoordY,A
        SUB  OffsetPosY,A
        STM  #DeltY,AR0
        DST  A,*AR0
        CALL TangleValue    ;Theta
        LD   Theta,A
        STL  A,*AR5+
        BANZ OFFSET_NEIGHBOR_LOOP,*AR7-      
        RSBX TC
EXIT_FINDMINUTIAE
        RSBX SXM
        POPM AR7
        POPM AR6
        POPM AR5
        POPM AR4
        POPM AR3
        POPM AR2
        POPM AR0
        RET

****************************************************************************
* check the neighbour point consist of mintiae point
****************************************************************************
        .text
PassMinutiae:
        PSHM  AR3
        PSHM  AR4
        PSHM  AR5
        PSHM  AR7
        SSBX  SXM
        LD    MinutiaePointer,A
        STLM  A,AR7
        STM   #AlphaArray,AR3
        LD    CoordX,A
        ADD   #STARTCOL,A
        STL   A,*AR7+          ;pFingerMinutiae->MinutiaePoint.x
        LD    CoordY,A
        ADD   #STARTROW,A
        STL   A,*AR7+          ;pFingerMinutiae->MinutiaePoint.y
        LD    OrientNum,A
        STL   A,*AR7+          ;pFingerMinutiae->MinutiaeMode=OrientNum
        SUB   #1,A
        BC    BURIFICATE_MINUTIAE,ANEQ
        MVDK  *AR3,Theta       ;Theta=AlphaArray[0]
        CALL  GetCosValue
        STM   #MIMUTIZELEN,T   ;MIMUTIZELEN*cos(theta)
        MPYA  B
        CMPM  Minus,#1
        BC    $21,TC
        CMPM  Minus,#4
        BC    $21,TC
        NEG   B
$21
        SFTA  B,-15,B
        ADD   CoordX,B                ;DistanceX=CoordX+Columns
        STL   B,DistanceX
        LD    *AR3,A
        STL   A,*AR7+                 ;pFingerMinutiae->MinutiaeAngle=Theta[0]
        BC    ERROR_PASSMINUTIAE,BLT  ;DistanceX<0
        SUB   #BLOCKSINX*BLOCKWIDTH,B
        BC    ERROR_PASSMINUTIAE,BGEQ ;DistanceX>=BLOCKSINX*BLOCKWIDTH
        CALL  GetSinValue
        MPYA  B                        ;MIMUTIZELEN*sin(theta)
        CMPM  Minus,#1
        BC    $22,TC
        CMPM  Minus,#4
        BC    $22,TC
        NEG   B
$22
        SFTA  B,-15,B
        ADD   CoordY,B               ;DistanceY=CoordY+Lines
        STL   B,DistanceY
        BC    ERROR_PASSMINUTIAE,BLT ;DistanceY<0
        SUB   #BLOCKSINY*BLOCKWIDTH,B
        BC    ERROR_PASSMINUTIAE,BGEQ ;DistanceY>=BLOCKSINY*BLOCKHEIGHT
        LD    DistanceY,-4,A         ;Lines=DistanceX/BLOCKHEIGHT
        STLM  A,T
        LD    DistanceX,-4,A         ;Columns=DistanceY/BLOCKWIDTH
        LD    #LightArray,B
        MAC   #BLOCKSINX,A
        ADD   A,B
        STLM  B,AR4                   ;LightArray[Lines][Columns]
        NOP
        NOP
        LD    *AR4,A
        BC    SUCCESS_PASSMINUTIAE,ANEQ
ERROR_PASSMINUTIAE
        SSBX  TC
        MAR   *+AR7(-4)
        B     EXIT_PASSMINUTIAE
BURIFICATE_MINUTIAE
        SUB   B,B 
        STM   #3,BK
        STL   A,OrientNum
        STLM  A,BRC
        STM   #DeltAlpha,AR3
        STM   #AlphaArray+1,AR4
        STM   #AlphaArray,AR5
        RPTB  DELET_ALPHA_LOOP-1
        LD    *AR5+,A
        ADD   #360,A
        SUB   *AR4+%,A
        RPT   #15
        SUBC  Divisor,A
        STH   A,*AR3
        LD    *AR3,A
        SUB   #180,A
        BC    $3,ALEQ
        SUB   #180,A
        STL   A,*AR3
$3
        MAR   *AR3+
        ADD   #1,B
DELET_ALPHA_LOOP
        ST    #0,MinOrient
        STM   #DeltAlpha,AR5
        LD    *AR5,A
        ABS   A
        MVDM  OrientNum,BRC
        STL   A,MinDeltAlpha
        SUB   B,B              ;OrientCount=0
        RPTB  FIND_MIN_MAX-1
        LD    *AR5,A
        ABS   A
        SUB   MinDeltAlpha,A
        BC    FIND_MIN_MAX_NEXT,AGEQ
        LD    *AR5,A
        ABS   A
        STL   A,MinDeltAlpha
        STL   B,MinOrient
FIND_MIN_MAX_NEXT
        MAR   *AR5+
        ADD   #1,B
FIND_MIN_MAX
        LD    MinOrient,A
        ADD   #AlphaArray,A,B
        STLM  B,AR5
        ADD   #DeltAlpha,A
        LD    #360,B
        ADD   *AR5,B
        STLM  A,AR5
        NOP
        NOP
        LD    *AR5,-1,A
        SUB   A,B
        RPT   #15
        SUBC  Divisor,B
        STH   B,*AR7+
SUCCESS_PASSMINUTIAE
        RSBX  TC
EXIT_PASSMINUTIAE
        LDM   AR7,A
        STL   A,MinutiaePointer
        RSBX  SXM
        POPM  AR7
        POPM  AR5
        POPM  AR4
        POPM  AR3
        RET


****************************************************************************
* Final delete unused minutiae information
****************************************************************************
        .text
FinalMinutiae:
	    SSBX  SXM
		ST    #360,Divisor
        LD    #1,A
        STM   #Buffer,AR7
        RPT   #MAXMINUTIAE-1
        STL   A,*AR7+
        
		STM   #GraySum,AR5       
		SUB   B,B             ;GraySize=0
	    DST   B,*AR5
		STM   #FreqArray,AR6
        STM   #LightArray,AR7
        STM   #BLOCKNUM-1,BRC
        RPTB  SUM_GRAY_VALUE-1
        LD    *AR7+,A
        SUB   #1,A
        BC    $12,AGT
		DLD   *AR5,A
        ADD   *AR6,A
		DST   A,*AR5
        ADD   #1,B
$12
        MAR   *AR6+
SUM_GRAY_VALUE
		SFTA  B,15,B
		SFTA  B,6,B
		DLD   *AR5,A
        CALL  DivideU32
		STLM  B,T
        STL   B,GrayLevel1
		STM   #DeltX,AR6
		STM   #DeltY,AR7
        MPY   GrayLevel1,B
        SFTA  B,-12
        STL   B,GrayLevel2

        LD    MinutiaeCount,A
		SUB   #2,A
        STL   A,MinutiaeCount 
        STLM  A,AR0 
        STM   FingerMinutiae,AR3    ;AR3=FingerMinutiae[BlockX]
        STM   #Buffer,AR4           ;AR4=Buffer[BlockX]==0?   
BLOCK_X_LOOP
        CMPM  *AR4,#0               
        BC    NEXT_BLOCK_X_LOOP,TC
        MVMM  AR4,AR2               ;AR2=Buffer[BlockY]==0? 
		MVMM  AR3,AR5               ;AR5=FingerMinutiae[BlockY]
		MVMM  AR0,AR1
		MAR   *AR2+
		MAR   *+AR5(4)
BLOCK_Y_LOOP
		CMPM  *AR2,#0               ;Buffer[BlockY]==0?   
        BC    NEXT_BLOCK_Y_LOOP,TC
        LD    *AR5+,B
        SUB   *AR3+,B
   		DST   B,*AR6                ;DistanceX=pFingerMinutiae[BlockY].x-pFingerMinutiae[BlockX].x
		ABS   B
        STL   B,DistanceX           
		
		LD    *AR5-,B
		SUB   *AR3-,B
        DST   B,*AR7                ;DistanceY=pFingerMinutiae[BlockY]-pFingerMinutiae[BlockX]
		ABS   B,A    
        STL   A,DistanceY       
  	    
		ADD   GrayLevel1,1,B        ;DistanceY<-BLOCKHEIGHT-2*GrayLevel1 
        ADD   #BLOCKHEIGHT,B
        BC    NEXT_BLOCK_Y_LOOP,BLT ;check DistanceY

        DLD   *AR6,B                ;DistanceX<-2*GrayLevel1
        ADD   GrayLevel1,1,B,A
        BC    NEXT_BLOCK_Y_LOOP,ALT

        SUB   GrayLevel1,1,B,A      ;DistanceX>2*GrayLevel1
        BC    NEXT_BLOCK_Y_LOOP,AGT

        LD    DistanceX,T
		MPY   DistanceX,A
		LD    DistanceY,T
		MAC   DistanceY,A
        STL   A,Distance          ;Distance=DistanceX*DistanceX+DistanceY*DistanceY
        SUB   GrayLevel2,-1,A,B   ;Distance<GrayLevel2/2
        BC    $4,BGEQ
        ST    #0,*AR4             ;Buffer[BlockX]=0
        ST    #0,*AR2             ;Buffer[BlockY]=0
        B     NEXT_BLOCK_X_LOOP
$4
        SUB   GrayLevel2,1,A      ;Distance<=3*GrayLevel2 
        SUB   GrayLevel2,A
        BC    $5,AGT

		MAR   *+AR3(3)
        MAR   *+AR5(3)
        LD    *AR5-,A             ;pFingerMinutiae[BlockIncY].MinutiaeAngle 
        SUB   *AR3-,A             ;pFingerMinutiae[BlockIncX].MinutiaeAngle
        ADD   #360,A
		MAR   *+AR3(-2)
        MAR   *+AR5(-2)
        RPT   #15
        SUBC  Divisor,A           ;Theta=(Theta+360)%360
		STH   A,Theta
		LD    Theta,A
		SUB   #180,A,B
        BC    $1,BLEQ             ;Theta>180??
        SUB   #360,A
        ABS   A                   ;Theta=abs(Theta-360)
$1
        SUB   #150,A              ;Theta<150
        BC    NEXT_BLOCK_Y_LOOP,ALT
        CALL  TangleValue
   		MAR   *+AR3(2)
        MAR   *+AR5(2)
	    CMPM  *AR3+,#1            ;pFingerMinutiae[BlockIncX].MinutiaeMode
        LD    *AR3-,B             ;Theta=pFingerMinutiae[BlockIncX].MinutiaeAngle-Theta
		BC    $6,NTC
        CMPM  *AR5,#1             ;pFingerMinutiae[BlockIncY].MinutiaeMode  
        BC    $6,NTC
		MAR   *AR5+
		LD    *AR5-,B             ;Theta=pFingerMinutiae[BlockIncY].MinutiaeAngle-Theta
$6
		MAR   *+AR3(-2)
        MAR   *+AR5(-2)
		SUB   Theta,B
        ADD   #360,B
        RPT   #15   
        SUBC  Divisor,B
        STH   B,Theta             ;Theta=(Theta+360)%360
		LD    Theta,A
        SUB   #180,A,B
        BC    $7,BLEQ             ;Theta=abs(Theta-360)
        SUB   #360,A
        ABS   A
		STL   A,Theta
$7
        SUB   #150,A              ;Theta<150  
        BC    NEXT_BLOCK_Y_LOOP,BLT
        ST    #0,*AR2
        ST    #0,*AR4
        B     NEXT_BLOCK_Y_LOOP
$5
        DLD   *AR7,A
        SUB   GrayLevel1,1,A
        SUB   #BLOCKHEIGHT,A
        BC    NEXT_BLOCK_X_LOOP,AGT
NEXT_BLOCK_Y_LOOP
        MAR   *AR2+
		MAR   *+AR5(4)
        BANZ  BLOCK_Y_LOOP,*AR1-
NEXT_BLOCK_X_LOOP
		MAR   *AR4+
		MAR   *+AR3(4)
		BANZ  BLOCK_X_LOOP,*AR0-
		       
        LD    MinutiaeCount,A
		ADD   #1,A
		STLM  A,AR7
        STM   #FingerMinutiae,AR4
		STM   #FingerMinutiae,AR5
		STM   #Buffer,AR6
        SUB   B,B         ;BlockY=0
LAST_MINUTIAE_OUT
        CMPM  *AR6+,#0
        BC    NEXT_LAST_MINUTIAE,TC
        RPT   #4-1
		MVDD  *AR4+,*AR5+
        ADD   #1,B
        MAR   *+AR4(-4)
NEXT_LAST_MINUTIAE
        MAR   *+AR4(4)
        BANZ  LAST_MINUTIAE_OUT,*AR7-
        STL   B,MinutiaeCount
		RSBX  SXM
        RET

;---------------------------------------------------------------------------
; do two finger property minutiae match,first find reference point
;---------------------------------------------------------------------------
		.text
MatchData:
		ST    #32,CheckCount

		ST    #0,MaxMatchPoint
		ST    #0,PointOfMatch
		STM   #Exist1,AR6
        RPTZ  A,MAXMINUTIAE-1
		STL   A,*AR6+
		STM   #Exist2,AR6
		RPTZ  A,MAXMINUTIAE-1
		STL   A,*AR6+
        
		LD    CheckCount,T
		MPY   MinutiaeCount ,A
        ST    #60,Divisor
		RPT   #15
		SUBC  Divisor,A
		STL   A,MatchThreshold     ;MatchThreshold=(nMinutiae*mMinutiae)/60

 		ST    #360,Divisor
        ST    #0,MinutiaeIndex 
		STM   #FingerMinutiae,AR1
MATCH_MINUTIAE_LOOP
        ST    #0,CheckIndex
        STM   #CheckMinutiae,AR2 
MATCH_CHECK_LOOP
		MAR   *+AR1(2)
		MAR   *+AR2(2)
		LD    *AR1,A
		SUB   *AR2,A
        MAR   *+AR1(-2)
		MAR   *+AR2(-2)
		BC    NEXT_MATCH_CHECK,ANEQ ;pFingerMinutiae[i].MinutiaeMode!=pCheckMinutiae[j].MinutiaeMode
		
		MAR   *+AR1(3)
		MAR   *+AR2(3)
		LD    *AR1,A
		ADD   #360,A
		SUB   *AR2,A
		RPT   #15
		SUBC  Divisor,A
		STH   A,Theta                ;Theta0=(pFingerMinutiae[i].MinutiaeAngle-pCheckMinutiae[j].MinutiaeAngle+360)%360
		LD    Theta,A
		MAR   *+AR1(-3)
		MAR   *+AR2(-3)
		SUB   #MAXDIFFEROFTHETA,A,B
		BC    STEP_MATCH_CHECK,BLEQ  ;Theta0>MAXDIFFEROFTHETA
		SUB   #360-MAXDIFFEROFTHETA,A,B
		BC    NEXT_MATCH_CHECK,BLT  ;Theta0<360-MAXDIFFEROFTHETA
STEP_MATCH_CHECK	
		STL   A,Theta0
		STL   A,Theta1
		CALL  GetCosValue   ;CosValue=cos(Theta*PI/180)
        CMPM  Minus,#1
        BC    $62,TC
        CMPM  Minus,#4
        BC    $62,TC
        NEG   A
$62
		STH   A,CosData0
		STH   A,CosValue
		CALL  GetSinValue   ;SinValue=sin(Theta*PI/180)
        CMPM  Minus,#1
        BC    $72,TC
        CMPM  Minus,#2
        BC    $72,TC
        NEG   A
$72
		STH   A,SinData0
		STH   A,SinValue
        LD    #CENTERROW,A
		SUB   *AR2+,A
        STL   A,DistanceX   ;DistanceX=pBlockInfo->CenterPoint.x-pCheckMinutiae[j].MinutiaePoint.x
        LD    #CENTERCOL,B
		SUB   *AR2+,B
		STL   B,DistanceY   ;DistanceY=pBlockInfo->CenterPoint.y-pCheckMinutiae[j].MinutiaePoint.y
        CALL  Cal_Coordinate  

		LD    #CENTERCOL,A
		SUB   CoordX,A
		SUB   *AR1+,A
		ABS   A                     ;abs(CoordinateX-pFingerMinutiae[i].MinutiaePoint.x)
		LD    #CENTERROW,B
		SUB   CoordY,B
		SUB   *AR1+,B
		ABS   B                     ;abs(CoordinateY-pFingerMinutiae[i].MinutiaePoint.y)
		ADD   A,B
		STL   B,Distance            ;Distance=abs()+abs()
		SUB   #MAXOFFSETDISTANCE,B
		MAR   *+AR1(-2)
		MAR   *+AR2(-2)
		BC    NEXT_MATCH_CHECK,BGT  ;Distance>MAXOFFSETDISTANCE
		
		STM   #Pos1,AR4
        LD    MinutiaeIndex,A
		STL   A,*AR4                ;Pos1[0]=i
		ADD   #Exist1,A
		STLM  A,AR3
		STM   #Pos2,AR4
		LD    CheckIndex,A
		ST    #1,*AR3               ;Exist1[i]=1
		ADD   #Exist2,A,B
		STLM  B,AR3
		STL   A,*AR4				;Pos2[0]=j
		LD    SinData0,A
		ST    #1,*AR3               ;Exist2[j]=1
		NEG   A
		STL   A,SinData0            ;sindata0=-sindata0
		ST    #1,PointOfMatch       ;PointOfMatch=1

        ST    #0,MinutiaeIndex1
        STM   #FingerMinutiae,AR3
MATCH_MINUTIAE_LOOP1
		LD    MinutiaeIndex1,A
		SUB   MinutiaeIndex,A
		BC    NEXT_MATCH_MINUTIAE1,AEQ   ;i1==i
        
		PSHM  AR1
		PSHM  AR6
		PSHM  AR7
		MVMM  AR3,AR6
		LD    CosData0,A
		STL   A,CosValue
		MVMM  AR2,AR7
		LD    SinData0,A
		STL   A,SinValue
		CALL  Cal_Distance
		POPM  AR7
		POPM  AR6
		POPM  AR1
		BC    NEXT_MATCH_MINUTIAE1,TC
		STL   B,Distance0
		CALL  TangleValue
		LD    Theta,A
		STL   A,Theta2

        ST    #0,CheckIndex1
        STM   #CheckMinutiae,AR4
MATCH_CHECK_LOOP1
		LD    CheckIndex,A
		SUB   CheckIndex1,A
		BC    NEXT_MATCH_CHECK1,AEQ
		
		MAR   *+AR3(2)
		MAR   *+AR4(2)
		LD    *AR3,A
		SUB   *AR4,A
		MAR   *+AR3(-2)
		MAR   *+AR4(-2)
		BC    NEXT_MATCH_CHECK1,ANEQ

        LD    *AR4+,A
		SUB   CoordX,A
		ABS   A
		STL   A,DistanceX
		LD    *AR4+,A
		SUB   CoordY,A
		ABS   A
		STL   A,DistanceY
		SQUR  DistanceX,A
		SQUR  DistanceY,B
		ADD   A,B
        SUB   Distance0,B
		MAR   *+AR4(-2)
		BC    NEXT_MATCH_CHECK1,BGT
        
		PSHM  AR5
		PSHM  AR6
		MVMM  AR3,AR5
		MVMM  AR4,AR6
		CALL  Check_Theta
		POPM  AR6
		POPM  AR5
        SUB   #15,A
		BC    NEXT_MATCH_CHECK1,AGT
		
		LD    *AR4+,A
		SUB   *AR2+,A
		STM   #DeltX,AR5
		DST   A,*AR5
        LD    *AR4+,A
		SUB   *AR2+,A
		STM   #DeltY,AR5
		DST   A,*AR5
		CALL  TangleValue
		LD    Theta,A
		STL   A,Theta3
		LD    Theta2,A
		ADD   #360,A
		SUB   Theta3,A
		RPT   #15
		SUBC  Divisor,A
		STH   A,Theta1
		MAR   *+AR2(-2)
		MAR   *+AR4(-2)

		ST    #2,PointOfMatch
		STM   #Pos1+1,AR6
        LD    MinutiaeIndex1,A
		STL   A,*AR6        ;Pos1[1]=i1
		ADD   #Exist1,A
		STLM  A,AR5
		STM   #Pos2+1,AR6
		LD    CheckIndex1,A
		ST    #1,*AR5       ;Exist1[i1]=1
		ADD   #Exist2,A,B
		STLM  B,AR5
		STL   A,*AR6		;Pos2[1]=j1
		LD    Theta1,A
		ST    #1,*AR5       ;Exist2[j1]=1
		STL   A,Theta
		CALL  GetCosValue   ;CosData1=cos(Theta*PI/180)
        CMPM  Minus,#1
        BC    $32,TC
        CMPM  Minus,#4
        BC    $32,TC
        NEG   A
$32
		STH   A,CosData1
		CALL  GetSinValue   ;SinData1=sin(Theta*PI/180)
        CMPM  Minus,#3
        BC    $42,TC
        CMPM  Minus,#4
        BC    $42,TC
        NEG   A
$42
		STH   A,SinData1
      
	    ST    #0,MinutiaeIndex2
        STM   #FingerMinutiae,AR5
		STM   #Exist1,AR0
MATCH_MINUTIAE_LOOP2
		LD    *AR0,A
		BC    NEXT_MATCH_MINUTIAE2,ANEQ

		PSHM  AR1
		PSHM  AR6
		PSHM  AR7
		MVMM  AR5,AR6
		LD    CosData1,A
		STL   A,CosValue
		MVMM  AR2,AR7
		LD    SinData1,A
		STL   A,SinValue
		CALL  Cal_Distance
		POPM  AR7
		POPM  AR6
		POPM  AR1
		BC    NEXT_MATCH_MINUTIAE2,TC
		STL   B,Distance1

        LD    CoordX,A
		STL   A,OldCoordX
		LD    CoordY,A
		STL   A,OldCoordY

		PSHM  AR1
		PSHM  AR6
		PSHM  AR7
		MVMM  AR5,AR6
		LD    CosData1,A
		STL   A,CosValue
		MVMM  AR3,AR1
		LD    SinData1,A
		STL   A,SinValue
		MVMM  AR4,AR7
		CALL  Cal_Distance
		POPM  AR7
		POPM  AR6
		POPM  AR1
		BC    NEXT_MATCH_MINUTIAE2,TC
		STL   B,Distance2

        ST    #0,CheckIndex2
        STM   #CheckMinutiae,AR6
		STM   #Exist2,AR7
MATCH_CHECK_LOOP2
		LD    *AR7,A
		BC    NEXT_MATCH_CHECK2,ANEQ
		MAR   *+AR5(2)
        MAR   *+AR6(2)
		LD    *AR5,A
		SUB   *AR6,A
		MAR   *+AR5(-2)
        MAR   *+AR6(-2)
		BC    NEXT_MATCH_CHECK2,ANEQ
        
		LD    *AR6+,A
		SUB   OldCoordX,A
		ABS   A
		STL   A,DistanceX
		LD    *AR6+,A
		SUB   OldCoordY,A
		ABS   A
		STL   A,DistanceY
        SQUR  DistanceX,A
		SQUR  DistanceY,B
		ADD   A,B
		SUB   Distance1,B
		MAR   *+AR6(-2)
		BC    NEXT_MATCH_CHECK2,BGT
        
		CALL  Check_Theta
        SUB   #15,A
		BC    NEXT_MATCH_CHECK2,AGT
	
		LD    *AR6+,A
		SUB   CoordX,A
		ABS   A
		STL   A,DistanceX
        LD    *AR6+,A
		SUB   CoordY,A
		ABS   A
		STL   A,DistanceY
        SQUR  DistanceX,A
		SQUR  DistanceY,B
		ADD   A,B           ;Distance=DistanceX*DistanceX+DistanceY*DistanceY
		SUB   Distance2,B
		MAR   *+AR6(-2)
		BC    NEXT_MATCH_CHECK2,BGT ;Distance>Distance2
		
		ST    #1,*AR0
		ST    #1,*AR7
		PSHM  AR0
		LD    PointOfMatch,A
		ADD   #Pos1,A,B
		STLM  B,AR0
		ADD   #Pos2,A
		LD    MinutiaeIndex2,B
		STL   B,*AR0
		STLM  A,AR0
		LD    CheckIndex2,B
		LD    PointOfMatch,A
		STL   B,*AR0
		ADD   #1,A
		STL   A,PointOfMatch    
		POPM  AR0
		LD    MaxMatchPoint,B
		MAX   B
		STL   B,MaxMatchPoint
;	    SUB   #MINMATCHPOINTS,A
;		BC    EXIT_MATCH_FINGER,AGEQ     ;PointOfMatch>=MINMATCHPOINTS??
NEXT_MATCH_CHECK2
		MAR   *+AR6(4)
        MAR   *AR7+
		LD    CheckIndex2,A
		ADD   #1,A
		STL   A,CheckIndex2
		SUB   CheckCount,A
		BC    MATCH_CHECK_LOOP2,ALT
NEXT_MATCH_MINUTIAE2
		MAR   *+AR5(4)
		MAR   *AR0+
		LD    MinutiaeIndex2,A
		ADD   #1,A
		STL   A,MinutiaeIndex2
		SUB   MinutiaeCount,A
		BC    MATCH_MINUTIAE_LOOP2,ALT

;		SQUR  PointOfMatch,A
;		SUB   MatchThreshold,A,B
;		BC    EXIT_MATCH_FINGER,BGEQ    ;PointOfMatch*PointOfMatch>=MatchThreshold
;		LD    PointOfMatch,A
;		SUB   #MinMATCHPOINTS,A,B
;		BC    EXIT_MATCH_FINGER,BGEQ    ;PointOfMatch>=MINMATCHPOINTS
        LD    PointOfMatch,A
		LD    MaxMatchPoint,B
		MAX   B
		STL   B,MaxMatchPoint
	
		PSHM  AR1
		SUB   #2,A
		STLM  A,BRC
		STM   #Pos1,AR0
		STM   #Pos2,AR7
		RPTB  CLEAR_EXIST-1
        LD    *AR0+,A
		ADD   #Exist1,A
		STLM  A,AR1
		LD    *AR7+,B
		ADD   #Exist2,B
		ST    #0,*AR1
		STLM  B,AR1
		NOP
		NOP
		ST    #0,*AR1		
		POPM  AR1
CLEAR_EXIST
		ST    #1,PointOfMatch
NEXT_MATCH_CHECK1
		MAR   *+AR4(4)
        LD    CheckIndex1,A
		ADD   #1,A
		STL   A,CheckIndex1
		SUB   CheckCount,A
		BC    MATCH_CHECK_LOOP1,ALT
NEXT_MATCH_MINUTIAE1
		MAR   *+AR3(4)
		LD    MinutiaeIndex1,A
		ADD   #1,A
		STL   A,MinutiaeIndex1
		SUB   MinutiaeCount,A
		BC    MATCH_MINUTIAE_LOOP1,ALT
NEXT_MATCH_CHECK
		MAR   *+AR2(4)
        LD    CheckIndex,A
		ADD   #1,A
		STL   A,CheckIndex
		SUB   CheckCount,A
		BC    MATCH_CHECK_LOOP,ALT
NEXT_MATCH_MINUTIAE
		MAR   *+AR1(4)
		LD    MinutiaeIndex,A
		ADD   #1,A
		STL   A,MinutiaeIndex
		SUB   MinutiaeCount,A
		BC    MATCH_MINUTIAE_LOOP,ALT
        RSBX  TC
		RET
EXIT_MATCH_FINGER
        SSBX  TC
		RET

;--------------------------------------------------------------------------------------------
		

